package org.wheel.plugins.toolkit.sql.capability;

import cn.hutool.core.lang.Pair;
import org.wheel.plugins.toolkit.sql.core.AbstractWrapper;
import org.wheel.plugins.toolkit.sql.core.Wrapper;
import org.wheel.plugins.toolkit.sql.enums.LogicalOp;
import org.wheel.plugins.toolkit.sql.helper.SFunction;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 分页功能
 * 游标 & Seek 都是「用业务键当游标」
 * 语法上放在 WHERE，语义上是分页起点
 * 与业务过滤器并列，但目的不同
 * 这样分类 = 官方标准 + 零破坏
 * @param <W> 子类型
 * @param <T> 实体类
 */
public interface LambdaPage<W extends LambdaPage<W, T>, T> {

    /* ---------- 快捷方法：物理分页（LIMIT/OFFSET） ---------- */
    default W page(int pageNo, int pageSize) {
        return pageLimit(pageNo, pageSize);
    }

    /* ---------- 快捷：深分页游标 WHERE cursorCol > cursorValue --------- */
    default W cursorPage(SFunction<T, ?> cursorCol, Object cursorValue) {
        return cursorPage(cursorCol, cursorValue, (AbstractWrapper<?, ?>)this);
    }

    default W cursorPage(SFunction<T, ?> cursorCol, Object cursorValue, AbstractWrapper<?, ?>  wrapper) {
        return pageCursor(cursorCol, cursorValue, wrapper);
    }

    /* ---------- 快捷：Seek 分页：WHERE (col1, col2) > (val1, val2) --------- */
    default W seekPage(SFunction<T, ?> col1, Object val1,
                       SFunction<T, ?> col2, Object val2,
                       Pair<SFunction<T, ?>, Object>... more) {
        List<Pair<SFunction<T, ?>, Object>> list = new ArrayList<>();
        if(more != null){
            Collections.addAll(list, more);
        }
        return seekPage((AbstractWrapper<?, ?>)this, col1, val1, col2, val2, list);
    }
    default W seekPage(AbstractWrapper<?, ?> wrapper, SFunction<T, ?> col1, Object val1,
                       SFunction<T, ?> col2, Object val2,
                       List<Pair<SFunction<T, ?>, Object>> list) {
        return pageSeek(LogicalOp.AND, wrapper, col1, val1, col2, val2, list);
    }

    /* ---------- 原子方法 – 由 LambdaQueryWrapper 实现类完成 ---------- */
    W pageCursor(SFunction<T, ?> cursorCol, Object cursorValue, AbstractWrapper<?, ?> wrapper);

    W pageSeek(LogicalOp logicalOp, AbstractWrapper<?, ?> wrapper, SFunction<T, ?> col1, Object val1,
                     SFunction<T, ?> col2, Object val2,
                     List<Pair<SFunction<T, ?>, Object>> more);

    W pageLimit(int pageNo, int pageSize);
}
